'''
Created on Oct 22, 2011

@author: conan
'''
import xml.etree.ElementTree
import re
from utils import getDir



class Yawl(object):
    ns = 'http://www.yawlfoundation.org/yawlschema'
    def __init__(self, yawlFile):
        self.yawlFile = yawlFile
        self.tree = xml.etree.ElementTree.ElementTree()
        self.tree.parse(self.yawlFile) 
        self._directory = getDir(self.yawlFile)
        self.trim('processControlElements')
        self.xtasks = [Xtask(e, self) for e in self.search('task')]
    
     
    
    def trim(self, tag):
        '''
        Trim the tree
        '''
        self.tree = self.search(tag)[0]
        
#TODO:Messy big time: be clear when to return a list and when to return an element
    def search(self, tags, attr=None, text=False, xelement=None):
        if not isinstance(tags, list):tags = [tags]
        if len(tags) == 1:
            rv = []
            if xelement == None: xelement = self.tree
            for i in  xelement.iter('{%s}%s' % (Yawl.ns, tags[0])): 
                if attr: 
                    rv += [i.get(attr)]
                elif text:
                    rv += [i.text]
                else:
                    rv += [i]
            return rv 
        elif len(tags) > 1:
            nodes = self.search(tags[0], attr, text, xelement)
            rv = []
            for n in nodes:
                rv += self.search(tags[1:], attr, text, n)
            return rv
    
    def fullScript(self):
        return '\n'.join(
                         (
                            'sp.directory="%s"' % self._directory 
                            , '\n'.join(t.script_init for t in self.xtasks)
                            , '\n'.join(t.script_config for t in self.xtasks if t.script_config)
                            , '\n'.join(t.script_bind for t in self.xtasks)
                            )
                         )
    
    @staticmethod
    def strip(tag):
        return re.sub(r'\{%s\}' % Yawl.ns, '', tag)

class Xtask(object):
    def __init__(self, element, yawl):
        self.text = element.text
        self.tag = Yawl.strip(element.tag) 
        self.name = yawl.search('name', text=True, xelement=element) 
        assert len(self.name) == 1, 'cannot find the name of the task'
        self.name = self.name[0]
        self.service = yawl.search('decomposesTo', attr='id', xelement=element)
        assert len(self.service) == 1, 'cannot find the service type (decomposition) of the task'
        self.service = self.service[0]
        self.initScripts(element, yawl)
            
    
    
    def initScripts(self, element, yawl):
#Initialization script
        self.script_init = '%s = %s("%s")\nsf.addTask(%s)' % (self.name,
                                                              self.service,
                                                              self.name,
                                                              self.name)
        
#Configuration script
        exprs = yawl.search('expression', attr='query', xelement=element) 
        if not isinstance(exprs, list):
            exprs = [exprs]
        self.script_config = ''
        for e in exprs:
            var_name, var_value = re.match(r"\<(.+?)>(.+?)<", e).groups()
            if var_name.startswith('sp') or var_name.startswith('sf'):
                #variables for sp or sf
                self.script_config += '%s=%s\n' % (var_name, var_value) 
            else:#local task variables
                self.script_config += '%s.%s=%s\n' % (self.name, var_name,
                                                      var_value)
                
#Binding script
        self.getSucc(element, yawl)
        self.script_bind = '\n'.join(['sf.connect("%s", "%s", "%s")' % (self.name, s[0], s[1]) 
                                      for s in self.succs])    
            

          
    def getSucc(self, element, yawl):
        self.succs = []
        flows = yawl.search('flowsInto', xelement=element) 
        if isinstance(flows, str): flows = [flows]  
        for f in flows:
            nextElement = yawl.search('nextElementRef', attr='id', xelement=f)
            assert len(nextElement) == 1, 'next element error for task %s' % self
            nextElement = nextElement[0]
            name = re.sub(r'_\d+', '', nextElement)
            postc = yawl.search('predicate', text=True, xelement=f) 
            postc = postc and postc[0] or 'lambda:True'
            if 'OutputCondition' != name:
                #exclude outputcondition
                self.succs.append((name, postc))
                                  
                
    def __repr__(self):
        return '<Xtask "%s">' % (self.name)


         
    

        
if __name__ == '__main__':  
    from SF import SF
    y = Yawl('../case/jobshop10by10/astar.yawl')
#    y = Yawl('../Case/sst/sst.yawl')
#    y = Yawl('../Case/tsp/tsp.yawl')
    print y.fullScript()
    sf = SF()
    sf.executeScript(y.fullScript())
    sf.run()


